/*
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 * The Original Code is iSQL-Viewer, A Mutli-Platform Database Tool.
 *
 * The Initial Developer of the Original Code is iSQL-Viewer, A Mutli-Platform Database Tool.
 * Portions created by Mark A. Kobold are Copyright (C) 2000-2007. All Rights Reserved.
 *
 * Contributor(s): 
 *  Mark A. Kobold [mkobold <at> isqlviewer <dot> com].
 *  
 * If you didn't download this code from the following link, you should check
 * if you aren't using an obsolete version: http://www.isqlviewer.com
 */
package org.isqlviewer.bookmarks;

import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import java.util.Date;
import java.util.Enumeration;
import java.util.Vector;

import org.isqlviewer.BindVariable;

/**
 * Bookmark for an SQL command(s).
 * <p>
 * Like any kind of bookmark metaphor this allows the creation of an object represent an SQL command or series of
 * commands. A bookmark can also represent a prepared statement with well formed data objects parameterized and
 * generated on the fly.
 * 
 * @author Mark A. Kobold &lt;mkobold at isqlviewer dot com&gt;
 * @version 1.0
 */
public class Bookmark extends BookmarkReference implements Cloneable {

    /**
     * Standard data-transfer flavor for DnD operations.
     */
    public static final DataFlavor BOOKMARK_FLAVOR = new DataFlavor(Bookmark.class, "iSQL-Viewer SQL Bookmark");

    private static final long serialVersionUID = 9004874440081925048L;
    // raw SQL text for this bookmark.
    private String commandText = null;
    // milliseconds for when this bookmark was last used.
    private Date lastAccess = null;
    // milliseconds for when this bookmark was created.
    private Date creationTime = null;
    // count for number of times this bookmark has been used.
    private long useCount = 0L;
    // collection of prepared parameters if any...
    private Vector<BindVariable> parameters = new Vector<BindVariable>();

    /**
     * Creates a new bookmark as child to the given folder.
     * <p>
     * Creating a bookmark will implictly add itself to the parentFolder given.
     * 
     * @param parentFolder that will contain this new bookmark instance.
     * @throws NullPointerException if the parentFolder null.
     */
    public Bookmark() {

    }

    @Override
    public Bookmark clone() {

        try {
            Bookmark copy = (Bookmark) super.clone();

            return copy;
        } catch (CloneNotSupportedException error) {
            throw new Error(error);
        }

    }

    @Override
    public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {

        if (BOOKMARK_FLAVOR.equals(flavor)) {
            return this;
        } else if (flavor.isFlavorTextType()) {
            return getCommandText();
        }
        throw new UnsupportedFlavorException(flavor);
    }

    @Override
    public DataFlavor[] getTransferDataFlavors() {

        return new DataFlavor[]{BOOKMARK_FLAVOR, DataFlavor.stringFlavor};
    }

    @Override
    public boolean isDataFlavorSupported(DataFlavor flavor) {

        if (flavor != null) {
            if (BOOKMARK_FLAVOR.equals(flavor) || flavor.isFlavorTextType()) {
                return true;
            }
        }
        return false;
    }

    /**
     * Date in milliseconds when this bookmark was created.
     * <p>
     * 
     * @return timestamp in milliseconds when this bookmark was created.
     */
    public Date getCreationTime() {

        return creationTime;
    }

    /**
     * Sets the creation time of this bookmark.
     * <p>
     * Typically this method will only be called when the bookmark is restored from local disk. Explicitly calling this
     * method otherwise will cause this value to essentially be invaild since it will not be true.
     * 
     * @param creationTime in milliseconds of the date this bookmark was created.
     */
    public void setCreationTime(Date creationTime) {

        this.creationTime = creationTime;
    }

    /**
     * Gets the last time this bookmark was executed against a JDBC connection.
     * <p>
     * 
     * @return timestamp in milliseconds when this bookmark was last executed.
     */
    public Date getLastAccess() {

        return lastAccess;
    }

    /**
     * Sets the last time this bookmark was executed against a JDBC connection.
     * <p>
     * 
     * @param lastAccess in milliseconds when this bookmark was last executed.
     */
    public void setLastAccess(Date lastUsedTime) {

        this.lastAccess = lastUsedTime;
    }

    /**
     * Gets the SQL command or commands contained in this bookmark.
     * <p>
     * Multiplie SQL commands can be combined within a bookarm using non-quoted semi-colon ';' to seperate the
     * statements.
     * 
     * @return the SQL command or commands of this bookmark.
     */
    public String getCommandText() {

        return commandText;
    }

    /**
     * Sets the SQL command or commands for this bookmark.
     * <p>
     * 
     * @param commandText command that will be this bookmark.
     */
    public void setCommandText(String sql) {

        this.commandText = sql;
    }

    /**
     * Gets the number of times this bookmark has been executed.
     * <p>
     * 
     * @return number times this bookmark has been executed.
     */
    public long getUseCount() {

        return useCount;
    }

    /**
     * Sets the number of times this bookmark has been executed.
     * <p>
     * If a negative number is used, then zero will be inferred as the inteded use count.
     * 
     * @param useCount new number of times this bookmark has been executed.
     */
    public void setUseCount(long useCount) {

        if (useCount < 0) {
            this.useCount = 0;
        } else {
            this.useCount = useCount;
        }
    }

    /**
     * Adds a bookmark parameter component to this bookmark.
     * <p>
     * When a bookmark represents a prepared statement, the bind variables for that statement are defined via the
     * bookmark parameter data object.
     * <p>
     * A prepared statement will only be attempted if and only if there are bookmark parameters defined within the
     * bookmark.
     * 
     * @param parameter to add to internal list of parameters.
     * @return <tt>true</tt> if the bookmark parameter was successfully added to this bookmark.
     */
    public boolean add(BindVariable parameter) {

        return parameters.add(parameter);
    }

    /**
     * Removes all bookmark parameters from this bookmark.
     * <p>
     * This call can be used to quickly ensure that this bookmark will not be interpreted as a prepared statement.
     */
    public void clearParameters() {

        parameters.clear();
    }

    /**
     * Gets an enumeration of the bookmark parameter data.
     * <p>
     * 
     * @return iterable object of bookmark parameters within this bookmark.
     */
    public Enumeration<BindVariable> variables() {

        return parameters.elements();
    }

    /**
     * Checks to see if this bookmark contains any parameters.
     * <p>
     * 
     * @return <tt>true</tt> if there are bookmark parameters contained in this instance.
     */
    public boolean containsParameters() {

        return !parameters.isEmpty();
    }

    /**
     * Removes a bookmark paramter by reference.
     * <p>
     * 
     * @param parameter to be removed from this bookmark.
     * @return <tt>true</tt> if the parameter was successfully removed from this bookmark.
     */
    public boolean removeParameter(BindVariable parameter) {

        return parameters.remove(parameter);
    }

    /**
     * Gets the number of prepared paramters that exist in this bookmark.
     * <p>
     * 
     * @return number of parameters that exist in this bookmark.
     */
    public int paremeterCount() {

        return parameters.size();
    }

    /**
     * @return
     */
    public BookmarkReference toBookmarkReference() {

        BookmarkReference reference = new BookmarkReference();
        reference.setFavorite(isFavorite());
        reference.setFolder(getFolder());
        reference.setId(getId());
        reference.setName(getName());
        reference.setColorLabel(getColorLabel());
        return reference;
    }
}
